/*
* Copyright (c) 2020 The canvas Authors. All rights reserved.
  Use of this source code is governed by a BSD-style license that can be
  found in the LICENSE file.

* Author:         dzlua - https://gitee.com/dzlua/canvas.git
* Email:          505544956@qq.com
* FileName:       canvas_2d_impl.cc
* Create Time:    2020/02/13 19:32:16
* Description:    /
*/

#include "canvas_2d_impl.h"

#include <string.h>

namespace cvs {
namespace c2d {
  Shape::Shape(ShapeType type) : type_(type) {}
  Shape::~Shape() {}
  ShapeType Shape::type() const { return type_; }

  ShapeLine::ShapeLine() : Shape(ShapeType::Line) {}
  ShapeLine::~ShapeLine() {}
  Result ShapeLine::reset() { pt1_ = pt2_ = Point(); return CVS_S_Ok; }
  Result ShapeLine::set(const Point &pt1, const Point &pt2) {
    pt1_ = pt1; pt2_ = pt2;
    return CVS_S_Ok;
  }
  Point ShapeLine::point1() const { return pt1_; }
  Point ShapeLine::point2() const { return pt2_; }

  ShapePolyline::ShapePolyline() : Shape(ShapeType::Polyline), points_(0), count_(0) {}
  ShapePolyline::~ShapePolyline() { reset(); }
  Result ShapePolyline::reset() {
    if (points_) {
      delete[] points_;
      points_ = 0;
    }
    count_ = 0;
    return CVS_S_Ok;
  }
  Result ShapePolyline::set(const Point *pts, uint count) {
    if (!pts || count == 0) return CVS_E_InvalidParam;
    reset();
    points_ = new Point[count];
    if (!points_) return CVS_E_OutOfMemory;
    for (uint i = 0; i < count; ++i)
      points_[i] = pts[i];
    count_ = count;
    return CVS_S_Ok;
  }
  Point* ShapePolyline::points() const { return points_; }
  uint ShapePolyline::count() const { return count_; }

  ShapeBezier::ShapeBezier() : Shape(ShapeType::Bezier) {}
  ShapeBezier::~ShapeBezier() { reset(); }
  Result ShapeBezier::reset() {
    pt0_ = pt1_ = pt2_ = pt3_ = Point();
    return CVS_S_Ok;
  }
  Result ShapeBezier::set(const BezierSegment &beizer) {
    return set(beizer.p0, beizer.p1, beizer.p2, beizer.p3);
  }
  Result ShapeBezier::set(const Point &pt0, const Point &pt1, const Point &pt2, const Point &pt3) {
    pt0_ = pt0; pt1_ = pt1; pt2_ = pt2; pt3_ = pt3;
    return CVS_S_Ok;
  }
  Point ShapeBezier::point0() const { return pt0_; }
  Point ShapeBezier::point1() const { return pt1_; }
  Point ShapeBezier::point2() const { return pt2_; }
  Point ShapeBezier::point3() const { return pt3_; }

  ShapeArc::ShapeArc() : Shape(ShapeType::Arc) {}
  ShapeArc::~ShapeArc() { reset(); }
  Result ShapeArc::reset() {
    start_ = end_ = Point();
    size_ = Size();
    angle_ = 0.f;
    sweep_ = large_ = false;
    return CVS_S_Ok;
  }
  Result ShapeArc::set(const ArcSegment &arc) {
    return set(arc.start, arc.end, arc.size, arc.angle, arc.sweep, arc.large);
  }
  Result ShapeArc::set(const Point &start, const Point &end, const Size &size, dtype angle, bool sweep, bool large) {
    start_ = start;
    end_ = end;
    size_ = size;
    angle_ = angle;
    sweep_ = sweep;
    large_ = large;
    return CVS_S_Ok;
  }
  Point ShapeArc::start() const { return start_; }
  Point ShapeArc::end() const { return end_; }
  Size ShapeArc::size() const { return size_; }
  dtype ShapeArc::angle() const { return angle_; }
  bool ShapeArc::sweep() const { return sweep_; }
  bool ShapeArc::large() const { return large_; }

  ShapePolygon::ShapePolygon() : Shape(ShapeType::Polygon), points_(0), count_(0) {}
  ShapePolygon::~ShapePolygon() { reset(); }
  Result ShapePolygon::reset() {
    if (points_) {
      delete[] points_;
      points_ = 0;
    }
    count_ = 0;
    return CVS_S_Ok;
  }
  Result ShapePolygon::set(const Point *pts, uint count) {
    if (!pts || count == 0) return CVS_E_InvalidParam;
    reset();
    points_ = new Point[count];
    if (!points_) return CVS_E_OutOfMemory;
    for (uint i = 0; i < count; ++i)
      points_[i] = pts[i];
    count_ = count;
    return CVS_S_Ok;
  }
  Point* ShapePolygon::points() const { return points_; }
  uint ShapePolygon::count() const { return count_; }

  ShapeRect::ShapeRect() : Shape(ShapeType::Rect) {}
  ShapeRect::~ShapeRect() { reset(); }
  Result ShapeRect::reset() { rect_ = Rect(); return CVS_S_Ok; }
  Result ShapeRect::set(const Rect &rect, const Size &radius) { rect_ = rect; radius_ = radius; return CVS_S_Ok; }
  Rect ShapeRect::rect() const { return rect_; }
  Size ShapeRect::radius() const { return radius_; }

  ShapeCircle::ShapeCircle() : Shape(ShapeType::Circle), radius_(0.f) {}
  ShapeCircle::~ShapeCircle() { reset(); }
  Result ShapeCircle::reset() { center_ = Point(); radius_ = 0.f; return CVS_S_Ok; }
  Result ShapeCircle::set(const Point &center, dtype radius) {
    center_ = center; radius_ = radius;
    return CVS_S_Ok;
  }
  Point ShapeCircle::center() const { return center_; }
  dtype ShapeCircle::radius() const { return radius_; }

  ShapeEllipse::ShapeEllipse() : Shape(ShapeType::Ellipse) {}
  ShapeEllipse::~ShapeEllipse() { reset(); }
  Result ShapeEllipse::reset() { center_ = Point(); radius_ = Size(); return CVS_S_Ok; }
  Result ShapeEllipse::set(const Point &center, const Size &radius) {
    center_ = center; radius_ = radius;
    return CVS_S_Ok;
  }
  Point ShapeEllipse::center() const { return center_; }
  Size ShapeEllipse::radius() const { return radius_; }

  ShapePath::ShapePath() : Shape(ShapeType::Path) {}
  ShapePath::~ShapePath() {}

  ShapeText::ShapeText() : Shape(ShapeType::Text), text_(0), len_(0) { reset(); }
  ShapeText::~ShapeText() { reset(); }
  Result ShapeText::reset() {
    text_ = 0; len_ = 0; rect_ = Rect();
    memset(&font_, 0, sizeof(font_));
    memset(&format_, 0, sizeof(format_));
    return CVS_S_Ok;
  }
  Result ShapeText::set(const wchar_t *text, uint len, const Rect &rect
          , const FontFormat &font, const TextFormat &format) {
    if (!text || len == 0) return CVS_E_InvalidParam;
    text_ = text; len_ = len; rect_ = rect;
    font_ = font; format_ = format;
    return CVS_S_Ok;
  }
  Rect ShapeText::rect() const { return rect_; }

  const wchar_t* ShapeText::font_family() const { return font_.family; }
  Result ShapeText::set_font_family(const wchar_t *family) {
    if (!family || !*family) return CVS_E_InvalidParam;
    font_.family = family;
    return CVS_S_Ok;
  }
  dtype ShapeText::font_size() const { return font_.size; }
  Result ShapeText::set_font_size(dtype size) {
    if (size <= 0.f) return CVS_E_InvalidParam;
    font_.size = size;
    return CVS_S_Ok;
  }
  bool ShapeText::font_italic() const { return font_.italic; }
  Result ShapeText::set_font_italic(bool italic) { font_.italic = italic; return CVS_S_Ok; }
  bool ShapeText::font_bold() const { return font_.bold; }
  Result ShapeText::set_font_bold(bool bold) { font_.bold = bold; return CVS_S_Ok; }
  bool ShapeText::font_strikethrough() const { return font_.strikethrough; }
  Result ShapeText::set_font_strikethrough(bool strikethrough) { font_.strikethrough = strikethrough; return CVS_S_Ok; }
  bool ShapeText::font_underline() const { return font_.underline; }
  Result ShapeText::set_font_underline(bool underline) { font_.underline = underline; return CVS_S_Ok; }
  //
  TextAlignHor ShapeText::text_hor_align() const { return format_.halign; }
  Result ShapeText::set_text_hor_align(const TextAlignHor align) { format_.halign = align; return CVS_S_Ok; }
  TextAlignVer ShapeText::text_ver_align() const { return format_.valign; }
  Result ShapeText::set_text_ver_align(const TextAlignVer align) { format_.valign = align; return CVS_S_Ok; }
  TextDirection ShapeText::text_direction() const { return format_.direction; }
  Result ShapeText::set_text_direction(const TextDirection direction) { format_.direction = direction; return CVS_S_Ok; }
  bool ShapeText::text_word_warp() const { return format_.word_wrap; }
  Result ShapeText::set_text_word_warp(bool word_wrap) { format_.word_wrap = word_wrap; return CVS_S_Ok; }
} // end namespace c2d
} // end namespace cvs